package framework.system.service.imp;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import framework.core.dao.IBaseDao;
import framework.core.util.Kit;
import framework.core.util.ListRange;
import framework.system.entity.SysResource;
import framework.system.entity.front.TreeNode;
import framework.system.service.IMenuService;

/**
 * @ClassName: MenuService 
 * @Description: 资源Service实现
 * @author: Ching Wang
 * @date 2013-5-18 下午2:29:07 
 *
 */
@Service
public class MenuService implements IMenuService {

	@Resource private IBaseDao<SysResource> resourceDao;
	
	/* 
	 * (非 Javadoc) 
	 * <p>Title: loadTree</p> 
	 * <p>Description: </p> 
	 * @param userId
	 * @param type
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#loadTree(java.lang.String, java.lang.String)
	 */
	@Override
	public List<TreeNode> loadTree(String userId, String type) throws Exception {
		List<TreeNode> tree = new ArrayList<TreeNode>();
		tree = this.getTree(userId, "", type);
		return tree;
	}
	/**
	 * @Title: getTree 
	 * @Description: 获取树节点 
	 * @param uid 用户ID
	 * @param pid 上级节点ID
	 * @param type 查询节点类型
	 * @return List<TreeNode>
	 * @throws Exception
	 */
	private List<TreeNode> getTree(String uid, String pid, String type) throws Exception{
		List<TreeNode> treeNodes = new ArrayList<TreeNode>();
		Map<String, Object> params = new HashMap<String, Object>();
		String hql = "select distinct(res) from SysResource res ";
		if(Kit.isNotNull(uid)){
			hql += " join res.sysRoles r join r.sysUsers u where 1 = 1 and u.id = :userId ";
			params.put("userId", uid);
		}
		else{
			hql += " where 1 = 1 ";
		}
		if("menu".equals(type)){
			hql += " and type = 'menu' ";
		}
		if(Kit.isNotNull(pid)){
			hql += " and res.sysResource.id = :resId order by res.seq asc ";
			params.put("resId", pid);
		}
		else{
			hql += " and res.sysResource is null order by res.seq asc ";
		}
		
		List<SysResource> list = resourceDao.find(hql, params);
		if(list != null && list.size() > 0){
			for(SysResource sysResource : list){
				treeNodes.add(tree(sysResource, uid, true, true, type));
			}
		}
		return treeNodes;
	}

	/**
	 * @Title: tree 
	 * @Description: 拼树节点
	 * @param sysResource 资源实体对象
	 * @param uid 用户编号
	 * @param recursive 是否递归
	 * @param isOpen 是否展开
	 * @param type 节点类型
	 * @return TreeNode
	 * @throws Exception
	 */
	private TreeNode tree(SysResource sysResource, String uid, boolean recursive, boolean isOpen, String type) throws Exception {
			TreeNode node = new TreeNode();
			BeanUtils.copyProperties(sysResource, node);
			SysResource pres = sysResource.getSysResource();
			if(pres != null){
				node.setPname(pres.getText());
				node.setPid(pres.getId());
			}
			
			if(sysResource.getUrl() != null && !"".equals(sysResource.getUrl())){
				Map<String, Object> attributes = new HashMap<String, Object>();
				attributes.put("url", sysResource.getUrl());
				node.setAttributes(attributes);
			}
			
			if(hasChildren(sysResource,type)){
				if(!isOpen){
					node.setState("closed");
				}
				if (recursive) {// 递归查询子节点
					node.setChildren(this.getTree(uid, sysResource.getId(), type));
				}
			}
			else{
				node.setState("open");
			}
			return node;
	}

	/**
	 * @Title: hasChildren 
	 * @Description: 判断是否有子节点
	 * @param sysResource 资源实体对象
	 * @param type 节点类型
	 * @return boolean
	 * @throws Exception
	 */
	private boolean hasChildren(SysResource sysResource, String type) throws Exception {
		DetachedCriteria criteria = DetachedCriteria.forClass(SysResource.class);
		criteria.add(Restrictions.eq("sysResource", sysResource));
		if("menu".equals(type)){
			criteria.add(Restrictions.eq("type", type));
		}
		return resourceDao.getCount(criteria) > 0;
	}

	/*
	 * (非 Javadoc) 
	 * <p>Title: getResource</p> 
	 * <p>Description: </p> 
	 * @param resouceId
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#getResource(java.lang.String)
	 */
	@Override
	public SysResource getResource(String resouceId) throws Exception {
		return resourceDao.findById(SysResource.class, resouceId);
	}

	/*
	 * (非 Javadoc) 
	 * <p>Title: getCount</p> 
	 * <p>Description: </p> 
	 * @param criteria
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#getCount(org.hibernate.criterion.DetachedCriteria)
	 */
	@Override
	public long getCount(DetachedCriteria criteria) throws Exception {
		return resourceDao.getCount(criteria);
	}

	/*
	 * (非 Javadoc) 
	 * <p>Title: saveOrUpdate</p> 
	 * <p>Description: </p> 
	 * @param resource
	 * @param opres
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#saveOrUpdate(framework.system.entity.SysResource, framework.system.entity.SysResource)
	 */
	@Override
	public void saveOrUpdate(SysResource resource, SysResource opres) throws Exception {
		if(Kit.isNotNull(resource.getId())){
			if(opres != resource.getSysResource()){
				delSeq(opres,resource.getSeq());
				addSeq(resource,"update");
			}
			resourceDao.update(resource);
		}
		else{
			addSeq(resource,"save");
			resourceDao.save(resource);
		}
	}

	/**
	 * @Title: addSeq 
	 * @Description: 更改或者设置资源顺序
	 * @param sysResource
	 * @param type
	 * @throws Exception
	 */
	private void addSeq(SysResource sysResource, String type) throws Exception {
		DetachedCriteria criteria = getCriteria(sysResource.getSysResource());
		long count = resourceDao.getCount(criteria);
		if("update".equals(type)){
			sysResource.setSeq(BigDecimal.valueOf(count));
		}
		else{
			sysResource.setSeq(BigDecimal.valueOf(count+1));
		}
	}

	/**
	 * @Title: delSeq 
	 * @Description: 删除节点时调整剩下节点顺序 
	 * @param pres 上级节点
	 * @param seq 当前节点序号
	 * @throws Exception
	 */
	private void delSeq(SysResource pres, BigDecimal seq) throws Exception {
		DetachedCriteria criteria = getCriteria(pres);
		criteria.add(Restrictions.gt("seq", seq));
		List<SysResource> list = resourceDao.findByCriteria(criteria);
		if(list != null && list.size() > 0){
			for(SysResource res : list){
				res.setSeq(new BigDecimal(res.getSeq().intValue()-1));
				resourceDao.update(res);
			}
		}
	}

	/** 
	 * @Title: getCriteria 
	 * @Description: 拼接查询条件
	 * @param pres 上级资源
	 * @return DetachedCriteria
	 */
	private DetachedCriteria getCriteria(SysResource pres) {
		DetachedCriteria criteria = DetachedCriteria.forClass(SysResource.class);
		if(pres != null){
			criteria.add(Restrictions.eq("sysResource.id", pres.getId()));
		}
		else{
			criteria.add(Restrictions.isNull("sysResource"));
		}
		return criteria;
	}

	/*
	 * (非 Javadoc) 
	 * <p>Title: delRes</p> 
	 * <p>Description: </p> 
	 * @param resIds
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#delRes(java.lang.String[])
	 */
	@Override
	public ListRange<TreeNode> delRes(String[] resIds) throws Exception {
		ListRange<TreeNode> range = new ListRange<TreeNode>();
		boolean flag = true;
		for(String resId : resIds){
			SysResource sysResource = resourceDao.findById(SysResource.class, resId);
			if(sysResource != null){
				if(sysResource.getSysRoles() != null && sysResource.getSysRoles().size() > 0){
					flag = false;
					range.setMessage("资源<font style='font-weight:bold;color:#ff0000;'>"+sysResource.getText()+"</font>正在使用中，请确认.");
					break;
				}
				else{
					delSeq(sysResource.getSysResource(),sysResource.getSeq());
					flag &= resourceDao.delete(sysResource);
					if(!flag){
						range.setMessage("删除资源信息失败，请确认.");
						break;
					}
				}
			}
		}
		range.setSuccess(flag);
		return range;
	}

	/*
	 * (非 Javadoc) 
	 * <p>Title: loadOper</p> 
	 * <p>Description: </p> 
	 * @param uid
	 * @param resId
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#loadOper(java.lang.String, java.lang.String)
	 */
	@Override
	public List<SysResource> loadOper(String uid, String resId) throws Exception {
		String hql = "select distinct(res) from SysResource res join res.sysRoles r join r.sysUsers u where u.id=:uid and res.type='button' and res.sysResource.id=:resid order by res.seq asc ";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("uid", uid);
		params.put("resid", resId);
		List<SysResource> list = resourceDao.find(hql, params);
		
		return list;//uniqSort(list);
	}

	/* 
	 * (非 Javadoc) 
	 * <p>Title: seqRes</p> 
	 * <p>Description: </p> 
	 * @param resId
	 * @param type
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#seqRes(java.lang.String, java.lang.String)
	 */
	@Override
	public ListRange<SysResource> seqRes(String resId, String type) throws Exception {
		boolean flag = false;
		ListRange<SysResource> range = new ListRange<SysResource>();
		SysResource resource = resourceDao.findById(SysResource.class, resId);
		if(resource != null){
			DetachedCriteria criteria = DetachedCriteria.forClass(SysResource.class);
			if("up".equals(type)){
				criteria.add(Restrictions.eq("seq", new BigDecimal(resource.getSeq().intValue() - 1)));
			}
			else{
				criteria.add(Restrictions.eq("seq", new BigDecimal(resource.getSeq().intValue() + 1)));
			}
			criteria.add(Restrictions.eq("sysResource", resource.getSysResource()));
			List<SysResource> resources = resourceDao.findByCriteria(criteria);
			if(resources != null && resources.size() > 0){
				SysResource nres = resources.get(0);
				if("up".equals(type)){
					resource.setSeq(new BigDecimal(resource.getSeq().intValue() -1));
					nres.setSeq(new BigDecimal(resource.getSeq().intValue() +1));
				}
				else{
					resource.setSeq(new BigDecimal(resource.getSeq().intValue() +1));
					nres.setSeq(new BigDecimal(resource.getSeq().intValue() -1));
				}
				resourceDao.update(resource);
				resourceDao.update(nres);
				flag = true;
			}
			else{
				if("up".equals(type)){
					range.setMessage("已经是最顶部资源，请确认.");
				}
				else{
					range.setMessage("已经是最底部资源，请确认.");
				}
			}
		}else{
			range.setMessage("未找到相关资源，请确认.");
		}
		range.setSuccess(flag);
		return range;
	}
	
	/* (非 Javadoc) 
	 * <p>Title: loadAut</p> 
	 * <p>Description: </p> 
	 * @param userId
	 * @param type
	 * @return
	 * @throws Exception 
	 * @see framework.system.service.IMenuService#loadAut(java.lang.String, java.lang.String) 
	 */
	@Override
	public Set<String> loadAut(String uid) throws Exception {
		Set<String> set = new HashSet<String>();
		List<SysResource> resources = new ArrayList<SysResource>();
		Map<String, Object> params = new HashMap<String, Object>();
		String hql = "select res from SysResource res  join res.sysRoles r join r.sysUsers u where 1 = 1 and u.id = :userId order by res.seq asc ";
		params.put("userId", uid);
		
		resources = resourceDao.find(hql, params);
		if (resources != null && resources.size() > 0) {
			for(SysResource resource : resources){
				set.add(resource.getUrl());
			}
		}
		return set;
	}
}
